﻿using System;
using System.Windows;
using System.Threading;
using System.ServiceModel;
using System.Windows.Media;
using System.Windows.Input;
using System.Windows.Controls;

using Builderator.Core;
using Builderator.Core.Interfaces;

using Builderator.Firefly.Windows;
using Builderator.Firefly.Controls;
using Builderator.Firefly.Properties;

namespace Builderator.Firefly
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    [ServiceBehavior(UseSynchronizationContext = false)]
    public partial class MainWindow : Window, IBuilderatorEngineCallback
    {
        public MainWindow()
        {
            InitializeComponent();

            this.Left = Settings.Default.WindowLocation.X;

            this.Top = Settings.Default.WindowLocation.Y;

            this.Width = Settings.Default.WindowSize.Width;

            this.Height = Settings.Default.WindowSize.Height;

            this.treeViewColumn.Width = new GridLength(Settings.Default.GridOne);

            this.historyRow.Height = new GridLength(Settings.Default.GridTwo);
        }

        private Point lastMosueDown;
        private DebugWindow debugWindow;
        private IBuilderatorEngine engineInterface;
        private SynchronizationContext syncContext;
        private BuilderatorEngine builderatorEngine;

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                this.rootTreeViewItem.Tag = Guid.Empty;

                this.debugWindow = new DebugWindow();

                this.builderatorEngine = new BuilderatorEngine();

                this.ConnectToDomain(this.builderatorEngine.AttachedHostname);

                this.syncContext = SynchronizationContext.Current;
            }
            catch (Exception)
            {

            }
        }

        private void ConnectToDomain(string address)
        {
            try
            {
                this.builderatorEngine.Connect(address);

                this.engineInterface = this.builderatorEngine.CreateServiceInstance(this, address);

                this.Title = string.Format("Builderator - {0}", address);

                this.BuildTreeAndMenus();

                this.jobDataGrid.ItemsSource = this.builderatorEngine.Jobs;
            }
            catch (Exception e)
            {
                this.OnDebugMessage(e.Message);

                this.OnDebugMessage(e.StackTrace);
            }
        }

        private void BuildTreeAndMenus()
        {
            this.rootTreeViewItem.Items.Clear();

            foreach (IAction projectAction in this.builderatorEngine.GetProjects())
            {
                TreeViewItem projectItem = new TreeViewItem();

                projectItem.Header = string.Format("Project: {0}", projectAction.Name);

                projectItem.Tag = projectAction.Identifier;

                foreach (IAction buildAction in this.builderatorEngine.GetBuilds(projectAction.Identifier))
                {
                    TreeViewItem buildItem = new TreeViewItem();

                    buildItem.Header = string.Format("Build: {0}", buildAction.Name);

                    buildItem.Tag = buildAction.Identifier;

                    TreeViewItem triggerItem = new TreeViewItem();

                    triggerItem.Header = "Triggers";

                    TreeViewItem actionItem = new TreeViewItem();

                    actionItem.Header = "Actions";

                    foreach (IAction pluginAction in this.builderatorEngine.GetActions(buildAction.Identifier))
                    {
                        TreeViewItem pluginItem = new TreeViewItem();

                        pluginItem.Tag = pluginAction.Identifier;

                        if (pluginAction is ITrigger)
                        {
                            pluginItem.Header = string.Format("Trigger: {0}", pluginAction.Name);

                            triggerItem.Items.Add(pluginItem);
                        }
                        else
                        {
                            pluginItem.Header = string.Format("Action: {0}", pluginAction.Name);

                            actionItem.Items.Add(pluginItem);
                        }
                    }

                    buildItem.Items.Add(triggerItem);

                    buildItem.Items.Add(actionItem);

                    projectItem.Items.Add(buildItem);
                }

                this.rootTreeViewItem.Items.Add(projectItem);
            }

            ContextMenu actionContextMenu = this.builderatorTreeView.Resources["pluginContextMenu"] as ContextMenu;
            ContextMenu triggerContextMenu = this.builderatorTreeView.Resources["triggerContextMenu"] as ContextMenu;

            foreach (IAction plugin in this.builderatorEngine.GetPlugins())
            {
                if (plugin is ITrigger)
                {
                    MenuItem item = new MenuItem();

                    item.Header = plugin.Name;

                    item.Tag = plugin.Type;

                    item.Click += new RoutedEventHandler(this.pluginItem_Click);

                    triggerContextMenu.Items.Add(item);
                }

                if (plugin is ISource)
                {
                    MenuItem item = new MenuItem();

                    item.Header = plugin.Name;

                    item.Tag = plugin.Type;

                    item.Click += new RoutedEventHandler(this.pluginItem_Click);

                    ((MenuItem)actionContextMenu.Items[0]).Items.Add(item);
                }

                if (plugin is ICompile)
                {
                    MenuItem item = new MenuItem();

                    item.Header = plugin.Name;

                    item.Tag = plugin.Type;

                    item.Click += new RoutedEventHandler(this.pluginItem_Click);

                    ((MenuItem)actionContextMenu.Items[1]).Items.Add(item);
                }

                if (plugin is IDeploy)
                {
                    MenuItem item = new MenuItem();

                    item.Header = plugin.Name;

                    item.Tag = plugin.Type;

                    item.Click += new RoutedEventHandler(this.pluginItem_Click);

                    ((MenuItem)actionContextMenu.Items[2]).Items.Add(item);
                }
            }
        }

        public void OnBuildUpdate()
        {
            SendOrPostCallback updateBuild = delegate
            {
                if (!(this.actionFrame.Content is BuilderatorSettingsControl))
                {
                    return;
                }

                TreeViewItem selectedItem = this.builderatorTreeView.SelectedItem as TreeViewItem;

                IAction selectedAction = (IAction)this.builderatorEngine.GetBuild((Guid)selectedItem.Tag);

                this.actionFrame.Content = new ActionControl(selectedAction);
            };

            this.syncContext.Post(updateBuild, null);
        }

        public void OnHistoryUpdate()
        {
            SendOrPostCallback updateHistory = delegate
            {
                this.jobDataGrid.ItemsSource = this.builderatorEngine.Jobs;
            };

            this.syncContext.Post(updateHistory, null);
        }

        public void OnDebugMessage(string message)
        {
            SendOrPostCallback setText = delegate
            {
                this.debugWindow.debugRun.Text += message + "\n";

                this.debugWindow.debugRichTextBox.ScrollToEnd();
            };

            this.syncContext.Post(setText, null);
        }

        private void treeViewItem_MouseDown(object sender, MouseButtonEventArgs e)
        {
            TreeViewItem selectedItem = sender as TreeViewItem;

            if (e.ChangedButton == MouseButton.Left)
            {
                this.lastMosueDown = e.GetPosition(this.builderatorTreeView);
            }
            else if (e.RightButton == MouseButtonState.Pressed)
            {
                if (selectedItem != null)
                {
                    selectedItem.Focus();

                    e.Handled = true;
                }

                string header = (string)selectedItem.Header;

                if (header.Contains(":"))
                    header = header.Substring(0, header.IndexOf(":"));

                switch (header)
                {
                    case "Builderator":
                        {
                            selectedItem.ContextMenu = this.builderatorTreeView.Resources["builderatorContextMenu"] as ContextMenu;
                        }
                        break;
                    case "Project":
                        {
                            selectedItem.ContextMenu = this.builderatorTreeView.Resources["projectContextMenu"] as ContextMenu;
                        }
                        break;
                    case "Build":
                        {
                            selectedItem.ContextMenu = this.builderatorTreeView.Resources["buildContextMenu"] as ContextMenu;
                        }
                        break;
                    case "Triggers":
                        {
                            selectedItem.ContextMenu = this.builderatorTreeView.Resources["triggerContextMenu"] as ContextMenu;
                        }
                        break;
                    case "Actions":
                        {
                            selectedItem.ContextMenu = this.builderatorTreeView.Resources["pluginContextMenu"] as ContextMenu;
                        }
                        break;
                    default:
                        selectedItem.ContextMenu = this.builderatorTreeView.Resources["actionContextMenu"] as ContextMenu;
                        break;
                }
            }

            e.Handled = true;
        }

        private void treeViewItem_Selected(object sender, EventArgs e)
        {
            TreeViewItem senderItem = sender as TreeViewItem;
            TreeViewItem selectedItem = this.builderatorTreeView.SelectedItem as TreeViewItem;

            if (senderItem.Header != selectedItem.Header)
                return;

            if (this.actionFrame.Content != null)
            {
                if (this.actionFrame.Content is ActionControl)
                {
                    ActionControl actionControl = (ActionControl)this.actionFrame.Content;

                    this.builderatorEngine.UpdateAction((IDatabase)actionControl.Action);
                }
                else
                {
                    BuilderatorSettingsControl settingsControl = (BuilderatorSettingsControl)this.actionFrame.Content;

                    settingsControl.Owner = this;

                    this.builderatorEngine.UpdateAction((IDatabase)settingsControl.settings);
                }
            }

            IDocument selectedAction = null;

            string header = selectedItem.Header as string;

            if (header.Contains(":"))
                header = header.Substring(0, header.IndexOf(":"));

            switch (header)
            {
                case "Builderator":
                    selectedAction = this.builderatorEngine.GetSettings();
                    break;
                case "Project":
                    selectedAction = (IDocument)this.builderatorEngine.GetProject((Guid)selectedItem.Tag);
                    break;
                case "Build":
                    selectedAction = this.builderatorEngine.GetBuild((Guid)selectedItem.Tag);
                    break;
                case "Trigger":
                case "Action":
                    selectedAction = (IDocument)this.builderatorEngine.GetAction((Guid)selectedItem.Tag);
                    break;
            }

            if (selectedAction == null) return;

            if (header == "Builderator")
            {
                BuilderatorSettingsControl control = new BuilderatorSettingsControl((BuilderatorSettings)selectedAction);

                control.Owner = this;

                control.DomainChangedEvent += new DomainChangedDelegate(control_DomainChangedEvent);

                this.actionFrame.Content = control;
            }
            else
            {
                this.actionFrame.Content = new ActionControl((IAction)selectedAction);
            }
        }

        private void control_DomainChangedEvent(object sender, DomainChangedEventArgs e)
        {
            try
            {
                IBuilderatorEngine remoteEngine;

                remoteEngine = this.builderatorEngine.CreateServiceInstance(this, e.Server.Name);

                switch (e.Status)
                {
                    case DomainChangedEventArgs.Changed.Added:
                        {
                            remoteEngine.AssignService(e.Server.Domain);
                        }
                        break;
                    case DomainChangedEventArgs.Changed.Removed:
                        {
                            remoteEngine.AssignService(e.Server.Name);
                        }
                        break;
                }

                BuilderatorSettingsControl control = this.actionFrame.Content as BuilderatorSettingsControl;

                this.builderatorEngine.UpdateAction((IDatabase)control.settings);
            }
            catch (Exception ex)
            {
                this.OnDebugMessage(ex.Message);

                this.OnDebugMessage(ex.StackTrace);
            }
        }

        private void projectMenuItem_Click(object sender, RoutedEventArgs e)
        {
            Guid projectIdentifier;
            UserInputWindow userInput = new UserInputWindow("Enter project name", "Project");

            userInput.Owner = this;

            if (userInput.ShowDialog() != true)
            {
                return;
            }

            projectIdentifier = this.builderatorEngine.CreateProject(userInput.UserInput);

            IAction projectAction = (IAction)this.builderatorEngine.GetProject(projectIdentifier);

            if (projectAction == null)
                return;

            TreeViewItem projectItem = new TreeViewItem();

            projectItem.Header = string.Format("Project: {0}", projectAction.Name);

            projectItem.Tag = projectAction.Identifier;

            this.rootTreeViewItem.Items.Add(projectItem);

            projectItem.Focus();
        }

        private void buildMenuItem_Click(object sender, RoutedEventArgs e)
        {
            Guid buildIdentifier;
            UserInputWindow userInput = new UserInputWindow("Enter build name", "Build name");

            userInput.Owner = this;

            if (userInput.ShowDialog() != true)
            {
                return;
            }

            TreeViewItem parent = this.builderatorTreeView.SelectedItem as TreeViewItem;

            buildIdentifier = this.builderatorEngine.CreateBuild(userInput.UserInput, (Guid)parent.Tag);

            IAction buildAction = (IAction)this.builderatorEngine.GetBuild(buildIdentifier);

            if (buildAction == null)
                return;

            TreeViewItem buildItem = new TreeViewItem();

            buildItem.Header = string.Format("Build: {0}", buildAction.Name);

            buildItem.Tag = buildAction.Identifier;

            TreeViewItem triggerItem = new TreeViewItem();

            triggerItem.Header = "Triggers";

            TreeViewItem actionsItem = new TreeViewItem();

            actionsItem.Header = "Actions";

            buildItem.Items.Add(triggerItem);

            buildItem.Items.Add(actionsItem);

            parent.Items.Add(buildItem);

            buildItem.Focus();
        }

        private void triggerItem_Click(object sender, RoutedEventArgs e)
        {
            Guid actionIdentifier;
            MenuItem pluginMenuItem = sender as MenuItem;

            TreeViewItem parent = this.builderatorTreeView.SelectedItem as TreeViewItem;

            actionIdentifier = this.builderatorEngine.CreateAction((Guid)((TreeViewItem)parent.Parent).Tag, (Guid)pluginMenuItem.Tag);

            IAction pluginAction = this.builderatorEngine.GetAction(actionIdentifier);

            if (pluginAction == null)
                return;

            TreeViewItem pluginItem = new TreeViewItem();

            pluginItem.Header = string.Format("Trigger: {0}", pluginAction.Name);

            pluginItem.Tag = pluginAction.Identifier;

            parent.Items.Add(pluginItem);

            pluginItem.Focus();
        }

        public void pluginItem_Click(object sender, RoutedEventArgs e)
        {
            Guid actionIdentifier;
            MenuItem pluginMenuItem = sender as MenuItem;

            TreeViewItem parent = this.builderatorTreeView.SelectedItem as TreeViewItem;

            actionIdentifier = this.builderatorEngine.CreateAction((Guid)((TreeViewItem)parent.Parent).Tag, (Guid)pluginMenuItem.Tag);

            IAction pluginAction = this.builderatorEngine.GetAction(actionIdentifier);

            if (pluginAction == null)
                return;

            TreeViewItem pluginItem = new TreeViewItem();

            pluginItem.Header = string.Format("Action: {0}", pluginAction.Name);

            pluginItem.Tag = pluginAction.Identifier;

            parent.Items.Add(pluginItem);

            this.actionFrame.Content = null;

            pluginItem.Focus();
        }

        private void deleteActionMenuItem_Click(object sender, RoutedEventArgs e)
        {
            TreeViewItem selectedItem = this.builderatorTreeView.SelectedItem as TreeViewItem;

            TreeViewItem parentItem = (TreeViewItem)LogicalTreeHelper.GetParent(selectedItem);

            this.builderatorEngine.DeleteAction((Guid)selectedItem.Tag);

            parentItem.Items.Remove(selectedItem);

            this.actionFrame.Content = null;
        }

        private void deleteBuildMenuItem_Click(object sender, RoutedEventArgs e)
        {
            TreeViewItem selectedItem = this.builderatorTreeView.SelectedItem as TreeViewItem;

            TreeViewItem parentItem = (TreeViewItem)LogicalTreeHelper.GetParent(selectedItem);

            this.builderatorEngine.DeleteBuild((Guid)selectedItem.Tag);

            parentItem.Items.Remove(selectedItem);

            this.actionFrame.Content = null;
        }

        private void deleteProjectMenuItem_Click(object sender, RoutedEventArgs e)
        {
            TreeViewItem selectedItem = this.builderatorTreeView.SelectedItem as TreeViewItem;

            TreeViewItem parentItem = (TreeViewItem)LogicalTreeHelper.GetParent(selectedItem);

            this.builderatorEngine.DeleteProject((Guid)selectedItem.Tag);

            parentItem.Items.Remove(selectedItem);

            this.actionFrame.Content = null;
        }


        private void runBuildMenuItem_Click(object sender, RoutedEventArgs e)
        {
            TreeViewItem buildTreeViewItem = this.builderatorTreeView.SelectedItem as TreeViewItem;

            ActionControl actionControl = (ActionControl)this.actionFrame.Content;

            this.builderatorEngine.UpdateAction((IDatabase)actionControl.Action);

            Thread thread = new Thread(delegate(object data)
                {
                    this.engineInterface.Subscribe();

                    this.engineInterface.RunBuild((Guid)data);
                });

            thread.Start(buildTreeViewItem.Tag);
        }

        private void runActionMenuItem_Click(object sender, RoutedEventArgs e)
        {
            TreeViewItem selectedItem = this.builderatorTreeView.SelectedItem as TreeViewItem;

            ActionControl actionControl = (ActionControl)this.actionFrame.Content;

            this.builderatorEngine.UpdateAction((IDatabase)actionControl.Action);

            Thread thread = new Thread(delegate(object data)
                {
                    this.engineInterface.Subscribe();

                    this.engineInterface.RunAction((Guid)data);
                });

            thread.Start(selectedItem.Tag);
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            try
            {
                Settings.Default.GridOne = (int)this.treeViewColumn.Width.Value;

                Settings.Default.GridTwo = (int)this.historyRow.Height.Value;

                Settings.Default.WindowLocation = new System.Drawing.Point((int)this.Left, (int)this.Top);

                Settings.Default.WindowSize = new System.Drawing.Size((int)this.Width, (int)this.Height);

                Settings.Default.Save();

                this.debugWindow.Dispose = true;

                this.debugWindow.Close();

                if (this.engineInterface != null)
                    this.engineInterface.Unsubscribe();
            }
            catch (Exception)
            {

            }
        }

        private void jobDataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            switch ((string)e.Column.Header)
            {
                case "Identifier":
                case "Associated":
                    e.Column.Visibility = System.Windows.Visibility.Hidden;
                    break;
            }
        }

        private void historyDeleteMenuItem_Click(object sender, RoutedEventArgs e)
        {
            Job[] deleteJobs = new Job[this.jobDataGrid.SelectedItems.Count];

            this.jobDataGrid.SelectedItems.CopyTo(deleteJobs, 0);

            foreach (Job job in deleteJobs)
            {
                this.builderatorEngine.DeleteJobHistory(job);
            }

            this.jobDataGrid.ItemsSource = this.builderatorEngine.Jobs;
        }

        private void ConnectBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            DomainBrowserWindow browser = new DomainBrowserWindow();

            browser.Owner = this;

            if (browser.ShowDialog() == false)
                return;

            this.ConnectToDomain(browser.Selected);
        }

        private void ExitBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            this.Close();
        }

        private void ViewDebugBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            if (this.debugWindow.IsVisible)
            {
                this.debugWindow.Hide();
            }
            else
            {
                this.debugWindow.Show();
            }
        }
    }
}